#include "DX11Water.h"
#include "ScreenManager.h"
#include "LightingManager.h"
#include "DX11ShaderManager.h"
#include "DX11TextureManager.h"
#include "Timer.h"
#include "DX11ErrorReport.h"
#include "CameraManager.h"
#include "AntTweakBarManager.h"

DX11Water::DX11Water()
{
	m_colour = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
}

DX11Water::~DX11Water()
{
	if (m_vertexBuffer) m_vertexBuffer->Release();
	if (m_indexBuffer) m_indexBuffer->Release();
	if (m_pConstantBuffer) m_pConstantBuffer->Release();
	if (m_pReflectionBuffer) m_pReflectionBuffer->Release();
	if (m_pReflectionTextureResource) m_pReflectionTextureResource->Release();
	if (m_pRefractionTextureResource) m_pRefractionTextureResource->Release();
}

bool DX11Water::Initialize(float size, float height)
{
	m_vertexData.push_back(
		VertexData(	D3DXVECTOR3(-size, height, -size), 
					D3DXVECTOR2(0.0f, 0.0f), 
					D3DXVECTOR3(0.0f, 1.0f, 0.0f))); 
	m_vertexData.push_back(
		VertexData(D3DXVECTOR3(size, height, -size), D3DXVECTOR2(1.0f, 0.0f), D3DXVECTOR3(0.0f, 1.0f, 0.0f))); 
	m_vertexData.push_back(
		VertexData(D3DXVECTOR3(-size, height, size), D3DXVECTOR2(0.0f, 1.0f), D3DXVECTOR3(0.0f, 1.0f, 0.0f))); 
	m_vertexData.push_back(
		VertexData(D3DXVECTOR3(size, height, size), D3DXVECTOR2(1.0f, 1.0f), D3DXVECTOR3(0.0f, 1.0f, 0.0f))); 

	m_indices.push_back(2);
	m_indices.push_back(1);
	m_indices.push_back(0);

	m_indices.push_back(3);
	m_indices.push_back(1);
	m_indices.push_back(2);

	D3D11_SAMPLER_DESC sampDesc;
	ZeroMemory( &sampDesc, sizeof(sampDesc) );
	sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
	sampDesc.MinLOD = 0;
	sampDesc.MaxLOD = D3D11_FLOAT32_MAX;

	HRESULT hr = TheScreenManager::Instance()->GetDevice()->CreateSamplerState(
		&sampDesc, &m_pTextureSamplerState);

	TheScreenManager::Instance()->InitBuffers(m_vertexBuffer, m_indexBuffer, m_bd, m_data,
												m_vertexData, m_indices, &m_pConstantBuffer);

	m_numOfIndices = m_indices.size();
	m_vertexData.clear();
	m_indices.clear();

	TheDX11TextureManager::Instance()->LoadTexture(L"../../Assets/water_texture.png");
	TheDX11TextureManager::Instance()->LoadTexture(L"../../Assets/water_normal_map2.jpg");
	TheDX11TextureManager::Instance()->LoadTexture(L"../../Assets/water_normal_map.jpg");
	TheDX11TextureManager::Instance()->LoadTexture(L"../../Assets/water_normal_map3.png");

	// initialise reflection buffer
	m_pReflectionBuffer = 0;
	D3D11_BUFFER_DESC desc;
	ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
	desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	desc.ByteWidth = sizeof(ReflectionBuffer);
	desc.CPUAccessFlags = 0;
	desc.MiscFlags = 0;
	desc.StructureByteStride = 0;
	desc.Usage = D3D11_USAGE_DEFAULT;

	hr = TheScreenManager::Instance()->GetDevice()->CreateBuffer(&desc, NULL, &m_pReflectionBuffer);
	if (FAILED(hr))
	{
		DX11ErrorMsg(L"Failed to initialise reflection buffer", L"DX11Water initialise", MB_OK);
	}




	return true;
}

void DX11Water::DrawWater()
{
	// get camera reflection view matrix and set it in m_rb
	//m_rb.m_reflectedView = TheCameraManager::Instance()->GetReflectedView();
	for (int i = 0; i != TheLightingManager::Instance()->GetNumberOfLights(); i++)
	{
		Light l = TheLightingManager::Instance()->GetLight(i + 1);
		m_cb.light[i].ambient = l.ambient;
		m_cb.light[i].colour = l.colour;
		m_cb.light[i].direction = l.direction;
		m_cb.light[i].attenuation = l.attenuation;
		m_cb.light[i].range = l.range;
		m_cb.light[i].enabled = l.enabled;
		m_cb.light[i].position = l.position;
		m_cb.light[i].pad = l.pad;
	}

	D3DXMatrixIdentity(&m_world);
	m_cb.m_outputColour = m_colour;
	m_cb.m_texturePosition = m_texturePosition;
	m_texturePosition.x += 0.01f * TheTimer::Instance()->GetDt();

	TheScreenManager::Instance()->SetBuffers(m_vertexBuffer, m_indexBuffer);
	m_cb.m_cameraPosition = TheCameraManager::Instance()->GetCameraPos();

	D3DXMatrixTranspose(&m_cb.m_world, &m_world);
	D3DXMatrixTranspose(&m_cb.m_view, &TheScreenManager::Instance()->GetViewMatrix());
	D3DXMatrixTranspose(&m_cb.m_projection, &TheScreenManager::Instance()->GetProjectionMatrix());
	
	D3DXMatrixTranspose(&m_cb.m_lightViewMatrix, &TheLightingManager::Instance()->GetLightViewMatrix());
	D3DXMatrixTranspose(&m_cb.m_lightProjMatrix, &TheLightingManager::Instance()->GetLightProjMatrix());

	TheScreenManager::Instance()->GetDeviceContext()->UpdateSubresource(m_pConstantBuffer, 0, NULL, &m_cb, 0, 0);
	//TheScreenManager::Instance()->GetDeviceContext()->UpdateSubresource(m_pReflectionBuffer, 0 , NULL, &m_rb, 1, 1);

	TheScreenManager::Instance()->GetDeviceContext()->VSSetShader(
		TheDX11ShaderManager::Instance()->UseShader("WaterShader").first, NULL, 0);
	TheScreenManager::Instance()->GetDeviceContext()->PSSetShader(
		TheDX11ShaderManager::Instance()->UseShader("WaterShader").second, NULL, 0);

	TheScreenManager::Instance()->GetDeviceContext()->VSSetConstantBuffers(0, 1, &m_pConstantBuffer);
	//TheScreenManager::Instance()->GetDeviceContext()->VSSetConstantBuffers(1, 1, &m_pReflectionBuffer);
	
	TheScreenManager::Instance()->GetDeviceContext()->PSSetConstantBuffers(0, 1, &m_pConstantBuffer);
	//TheScreenManager::Instance()->GetDeviceContext()->PSSetConstantBuffers(1, 1, &m_pReflectionBuffer);

	TheScreenManager::Instance()->GetDeviceContext()->PSSetShaderResources(0, 1, &m_pRefractionTextureResource);
	TheScreenManager::Instance()->GetDeviceContext()->PSSetShaderResources(1, 1, &m_pReflectionTextureResource);
	TheScreenManager::Instance()->GetDeviceContext()->PSSetShaderResources(2, 1,
		&TheDX11TextureManager::Instance()->UseTexture(L"../../Assets/water_texture.png"));
	TheScreenManager::Instance()->GetDeviceContext()->PSSetShaderResources(3, 1,
		&TheDX11TextureManager::Instance()->UseTexture(L"../../Assets/water_normal_map2.jpg"));
	TheScreenManager::Instance()->GetDeviceContext()->PSSetShaderResources(4, 1,
		&TheDX11TextureManager::Instance()->UseTexture(L"../../Assets/water_normal_map3.png"));

	TheScreenManager::Instance()->GetDeviceContext()->PSSetSamplers(0, 1, &m_pTextureSamplerState);
	
	TheScreenManager::Instance()->GetDeviceContext()->DrawIndexed(m_numOfIndices, 0, 0);
}

void DX11Water::Draw()
{
	DrawWater();
}

void DX11Water::Update()
{
	
}

void DX11Water::GetPosition(D3DXVECTOR3& pos)
{
	pos = m_position;
}

void DX11Water::SetRefractionTexture(ID3D11ShaderResourceView* tex)
{
	m_pRefractionTextureResource = tex;
}

void DX11Water::SetReflectionTexture(ID3D11ShaderResourceView* tex)
{
	m_pReflectionTextureResource = tex;
}

void DX11Water::SetColour(const D3DXVECTOR4& colour)
{
	m_colour = colour;
}